﻿using System;
using System.Collections.Generic;
using Eirene.Core.Model;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Eirene.CLI.UnitTests.Model
{
	/// <summary>
	/// Test behaviour of ItemContainer.
	/// </summary>
	[TestClass()]
	public class ItemContainerTest
	{
		////[TestMethod]
		////[Timeout(5000)]
		////public void ValidateConsoleOutput()
		////{
		////    using (StringWriter sw = new StringWriter())
		////    {
		////        Console.SetOut(sw);

		////        var container = new ItemContainer();
		////        container.ItemNameIsNotUnique("Santa Hat");

		////        string expectedOutput = string.Format("There is already an item with this name!", Environment.NewLine);
		////        Assert.AreEqual(expectedOutput, sw.ToString());
		////    }
		////}

		[TestMethod]
		public void Create_WithNoItems()
		{
			var target = new ItemContainer(new List<Item> { });

			Assert.AreEqual(0, target.Count);

			var newItem1 = new Item
			{
				ItemName = "Sun Hat",
				Colour = "Blue",
				Price = 19.95m,
				Owners = new List<Owner>() 
						{ 
							new Owner { FirstName="Mickey", LastName="Mouse" } 
						},
				Status = new Status("New")
			};

			var newItem2 = new Item
			{
				ItemName = "Fedora",
				Colour = "Black",
				Price = 45.95m,
				Owners = new List<Owner>() 
						{ 
							new Owner { FirstName="Donald", LastName="Duck" } 
						},
				Status = new Status("Rented")
			};

			var container = new ItemContainer();
			container.Add(newItem1);
			container.Add(newItem2);

			Assert.AreEqual(2, container.Count);
		}

		[TestMethod]
		public void Add_ItemNameIsNotUnique()
		{
			// arrange
			string newItemName = "Santa Hat";
			var existingItem = new Item
			{
				ItemName = "Santa Hat",
				Colour = "Red",
				Price = 19.95m,
				Owners = new List<Owner>() 
						{ 
							new Owner { FirstName="Mickey", LastName="Mouse" } 
						},
				Status = new Status("New")
			};

			var container = new ItemContainer();
			container.Add(existingItem);

			// act
			bool result = container.ItemNameIsNotUnique(newItemName);
			
			// assert
			Assert.IsTrue(result);
		}

		[TestMethod]
		public void Add_ItemNameIsUnique()
		{
			// arrange
			string newItemName = "Sun Hat";
			var existingItem = new Item
			{
				ItemName = "Santa Hat",
				Colour = "Red",
				Price = 19.95m,
				Owners = new List<Owner>() 
						{ 
							new Owner { FirstName="Mickey", LastName="Mouse" } 
						},
				Status = new Status("New")
			};

			var container = new ItemContainer();
			container.Add(existingItem);

			// act
			bool result = container.ItemNameIsNotUnique(newItemName);

			// assert
			Assert.IsFalse(result);
		}

		[TestMethod]
		public void Add_NoDefaultOwner_DefaultAssigned()
		{
			// arrange
			var owner1 = new Owner { FirstName = "Minnie", LastName = "Mouse", IsDefault = false };
			var owner2 = new Owner { FirstName = "Daisy", LastName = "Duck", IsDefault = false };
			var owner3 = new Owner { FirstName = "Olive", LastName = "Oil", IsDefault = false };

			var newItem = new Item
			{
				ItemName = "Sun Hat",
				Colour = "Blue",
				Price = 19.95m,
				Owners = new List<Owner>() 
						{ 
							owner1,
							owner2,
							owner3
						},
				Status = new Status("New")
			};

			var container = new ItemContainer();
			container.Add(newItem);

			// act
			List<Owner> owners = container.SetDefaultOwner(newItem.Owners);

			// assert
			Assert.IsTrue(owners[0].IsDefault == true);
		}

		[TestMethod]
		public void Add_NoOwners_DefaultAssigned()
		{
			// arrange
			var newItem = new Item
			{
				ItemName = "Sun Hat",
				Colour = "Blue",
				Price = 19.95m,
				Owners = new List<Owner>(),
				Status = new Status("New")
			};

			var container = new ItemContainer();
			container.BaseDefaultOwner = new Owner { FirstName = "Minnie", LastName = "Mouse", IsDefault = true };

			// act
			container.Add(newItem);
			List<Owner> owners = newItem.Owners;

			// assert
			Assert.IsTrue(owners.Count == 1);
			Assert.AreEqual("Minnie", owners[0].FirstName);
			Assert.AreEqual("Mouse", owners[0].LastName);
			Assert.IsTrue(owners[0].IsDefault == true);
		}

		[TestMethod]
		public void Add_OwnerListIsDistinct()
		{
			// arrange
			var owner1 = new Owner { FirstName = "Minnie", LastName = "Mouse" };
			var owner2 = new Owner { FirstName = "Daisy", LastName = "Duck" };
			var owner3 = new Owner { FirstName = "Minnie", LastName = "Mouse" };

			var newItem = new Item
			{
				ItemName = "Santa Hat",
				Colour = "Red",
				Price = 19.95m,
				Owners = new List<Owner>() 
						{ 
							owner1,
							owner2,
							owner3
						},
				Status = new Status("New")
			};

			var container = new ItemContainer();
			container.Add(newItem);

			// act
			List<Owner> distinctList = container.DistinctOwnerList(newItem.Owners);

			// assert
			Assert.IsTrue(distinctList.Count == 2);
		}

		[TestMethod]
		public void SingleParameter_Add_EmptyColour_ExceptionThrown()
		{
			// arrange
			var TestMethodItem = new Item
			{
				ItemName = "Sun Hat",
				Colour = String.Empty,
				Price = 19.95m,
				Owners = new List<Owner>() 
						{ 
							new Owner { FirstName="Mickey", LastName="Mouse" } 
						},
				Status = new Status("New")
			};

			var container = new ItemContainer();

			// act
			Exception exError = null;
			try
			{
				container.Add(TestMethodItem);
			}
			catch (ArgumentException ex)
			{
				exError = ex;
			}

			// assert
			Assert.IsNotNull(exError);
			Assert.AreEqual(0, container.Count);
		}

		[TestMethod]
		public void SingleParameter_Add_EmptyItemName_ExceptionThrown()
		{
			// arrange
			var TestMethodItem = new Item
			{
				ItemName = String.Empty,
				Colour = "Blue",
				Price = 19.95m,
				Owners = new List<Owner>() 
						{ 
							new Owner { FirstName="Mickey", LastName="Mouse" } 
						},
				Status = new Status("New")
			};

			var container = new ItemContainer();

			// act
			Exception exError = null;
			try
			{
				container.Add(TestMethodItem);
			}
			catch (ArgumentException ex)
			{
				exError = ex;
			}

			// assert
			Assert.IsNotNull(exError);
			Assert.AreEqual(0, container.Count);
		}
		
		[TestMethod]
		public void SingleParameter_Add_NullColour_ExceptionThrown()
		{
			// arrange
			var TestMethodItem = new Item
			{
				ItemName = "Sun Hat",
				Colour = null,
				Price = 19.95m,
				Owners = new List<Owner>() 
						{ 
							new Owner { FirstName="Mickey", LastName="Mouse" } 
						},
				Status = new Status("New")
			};

			var container = new ItemContainer();

			// act
			Exception exError = null;
			try
			{
				container.Add(TestMethodItem);
			}
			catch (ArgumentException ex)
			{
				exError = ex;
			}

			// assert
			Assert.IsNotNull(exError);
			Assert.AreEqual(0, container.Count);
		}

		[TestMethod]
		public void SingleParameter_Add_NullItem_ExceptionThrown()
		{
			var container = new ItemContainer();

			// act
			Exception exError = null;
			try
			{
				container.Add(null);
			}
			catch (ArgumentNullException ex)
			{
				exError = ex;
			}

			// assert
			Assert.IsNotNull(exError);
			Assert.AreEqual(0, container.Count);
		}

		[TestMethod]
		public void SingleParameter_Add_NullItemName_ExceptionThrown()
		{
			// arrange
			var TestMethodItem = new Item
			{
				ItemName = null,
				Colour = "Blue",
				Price = 19.95m,
				Owners = new List<Owner>() 
						{ 
							new Owner { FirstName="Mickey", LastName="Mouse" } 
						},
				Status = new Status("New")
			};

			var container = new ItemContainer();

			// act
			Exception exError = null;
			try
			{
				container.Add(TestMethodItem);
			}
			catch (ArgumentException ex)
			{
				exError = ex;
			}

			// assert
			Assert.IsNotNull(exError);
			Assert.AreEqual(0, container.Count);
		}

		[TestMethod]
		public void SingleParameter_Add_NullOwners_ExceptionThrown()
		{
			// arrange
			var TestMethodItem = new Item
			{
				ItemName = "Sun Hat",
				Colour = "Blue",
				Price = 19.95m,
				Owners = null,
				Status = new Status("New")
			};

			var container = new ItemContainer();

			// act
			Exception exError = null;
			try
			{
				container.Add(TestMethodItem);
			}
			catch (ArgumentNullException ex)
			{
				exError = ex;
			}

			// assert
			Assert.IsNotNull(exError);
			Assert.AreEqual(0, container.Count);
		}

		[TestMethod]
		public void SingleParameter_Add_NullStatus_ExceptionThrown()
		{
			// arrange
			var TestMethodItem = new Item
			{
				ItemName = "Sun Hat",
				Colour = "Blue",
				Price = 19.95m,
				Owners = new List<Owner>() 
						{ 
							new Owner { FirstName="Mickey", LastName="Mouse" } 
						},
				Status = null
			};

			var container = new ItemContainer();

			// act
			Exception exError = null;
			try
			{
				container.Add(TestMethodItem);
			}
			catch (ArgumentException ex)
			{
				exError = ex;
			}

			// assert
			Assert.IsNotNull(exError);
			Assert.AreEqual(0, container.Count);
		}

		[TestMethod]
		public void SingleParameter_Add_Success()
		{
			// arrange
			var TestMethodItem = new Item
			{
				ItemName = "Sun Hat",
				Colour = "Blue",
				Price = 19.95m,
				Owners = new List<Owner>() 
						{ 
							new Owner { FirstName="Mickey", LastName="Mouse", IsDefault=true } 
						},
				Status = new Status("New")
			};

			var container = new ItemContainer();

			// act
			container.Add(TestMethodItem);

			// assert
			Assert.AreEqual(1, container.Count);
			//Assert.IsTrue(container.Exists(i => i.ItemName == TestMethodItem.ItemName));
			//Assert.IsTrue(container.Exists(i => i.Colour == TestMethodItem.Colour));
			//Assert.IsTrue(container.Exists(i => i.Price == TestMethodItem.Price));
			//Assert.IsTrue(container.Exists(i => i.Owners == TestMethodItem.Owners));
		}
	}
}
